
// Copyright (C) 2012 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;

using Derm.OpenGL;
using Derm.Raster;
using Derm.Render;

namespace Derm.Xml.Collada
{
	/// <summary>
	/// The fx_color_common simple type.
	/// </summary>
	public class ColladaFxColorType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxColorType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxColorType.
		/// </param>
		public ColladaFxColorType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region FX Color Type

		/// <summary>
		/// The color components.
		/// </summary>
		public ColorRGBAF Value;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the element text of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		public override void ReadText(XmlReader xmlReader)
		{
			if (xmlReader  == null)
				throw new ArgumentNullException("xmlReader");

			float[] values = XmlHelper.ReadXmlListOfFloats(xmlReader);

			Value = new ColorRGBAF(values[0], values[1], values[2], values[3]);
		}

		#endregion
	}

	/// <summary>
	/// The fx_opaque_enum simple type.
	/// </summary>
	public enum ColladaFxOpaqueType
	{
		/// <summary>
		/// When a transparent opaque attribute is set to A_ONE, it means the transparency information will be taken from the alpha channel of
		/// the color, texture, or parameter supplying the value. The value of 1.0 is opaque in this mode.
		/// </summary>
		AlphaOne,
		/// <summary>
		/// When a transparent opaque attribute is set to RGB_ZERO, it means the transparency information will be taken from the red, green, and
		/// blue channels of the color, texture, or parameter supplying the value. Each channel is modulated independently. The value of 0.0 is opaque in this mode.
		/// </summary>
		RgbZero
	}

	/// <summary>
	/// 
	/// </summary>
	public enum ColladaFxModifier
	{
		None,
		[XmlEnum("CONST")]
		Constant,
		[XmlEnum("UNIFORM")]
		Uniform,
		[XmlEnum("VARYING")]
		Varying,
		[XmlEnum("STATIC")]
		Static,
		[XmlEnum("VOLATILE")]
		Volatile,
		[XmlEnum("EXTERN")]
		Extern,
		[XmlEnum("SHARED")]
		Shared,
	}

	#region Samplers

	/// <summary>
	/// 
	/// </summary>
	public enum ColladaFxSamplerWrap
	{
		/// <summary>
		/// 
		/// </summary>
		None,
		/// <summary>
		/// Wrap texture coordinates.
		/// </summary>
		[XmlEnum("WRAP")]
		Wrap,
		/// <summary>
		/// Mirror texture coordinates.
		/// </summary>
		[XmlEnum("MIRROR")]
		Mirror,
		/// <summary>
		/// Clamp texture coordinates.
		/// </summary>
		[XmlEnum("CLAMP")]
		Clamp,
		/// <summary>
		/// 
		/// </summary>
		[XmlEnum("BORDER")]
		Border
	}

	/// <summary>
	/// 
	/// </summary>
	public enum ColladaFxSamplerFilter
	{
		/// <summary>
		/// No filter specified.
		/// </summary>
		[XmlEnum("NONE")]
		None,
		/// <summary>
		/// Nearest filtering.
		/// </summary>
		[XmlEnum("NEAREST")]
		Nearest = Gl.NEAREST,
		/// <summary>
		/// Linear filtering.
		/// </summary>
		[XmlEnum("LINEAR")]
		Linear = Gl.LINEAR,
		/// <summary>
		/// 
		/// </summary>
		[XmlEnum("NEAREST_MIPMAP_NEAREST")]
		NearestMipmapNearest = Gl.NEAREST_MIPMAP_NEAREST,
		/// <summary>
		/// 
		/// </summary>
		[XmlEnum("LINEAR_MIPMAP_NEAREST")]
		LinearMipmapNearest = Gl.LINEAR_MIPMAP_NEAREST,
		/// <summary>
		/// 
		/// </summary>
		[XmlEnum("NEAREST_MIPMAP_LINEAR")]
		NearestMipmapLinear = Gl.NEAREST_MIPMAP_LINEAR,
		/// <summary>
		/// 
		/// </summary>
		[XmlEnum("LINEAR_MIPMAP_LINEAR")]
		LinearMipmapLinear = Gl.LINEAR_MIPMAP_LINEAR
	}

	/// <summary>
	/// 
	/// </summary>
	public enum ColladaFxSamplerType
	{
		Sampler1D,
		Sampler2D,
		Sampler3D,
		SamplerCube,
		SamplerRect,
		SamplerDepth,
	}

	/// <summary>
	/// 
	/// </summary>
	public class ColladaFxSampler : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSampler.
		/// </summary>
		/// <param name="type">
		/// The sampler type.
		/// </param>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSampler.
		/// </param>
		public ColladaFxSampler(ColladaFxSamplerType type, ColladaXmlSerializable parent) : base(parent)
		{
			Type = type;
		}

		#endregion

		#region FX Sampler Information

		/// <summary>
		/// The sampler type.
		/// </summary>
		public readonly ColladaFxSamplerType Type;

		/// <summary>
		/// 
		/// </summary>
		public string Source;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerWrap WrapS = ColladaFxSamplerWrap.Wrap;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerWrap WrapT = ColladaFxSamplerWrap.Wrap;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerWrap WrapP = ColladaFxSamplerWrap.Wrap;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerFilter FilterMin = ColladaFxSamplerFilter.None;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerFilter FilterMag = ColladaFxSamplerFilter.None;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSamplerFilter FilterMip = ColladaFxSamplerFilter.None;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxColorType BorderColor;

		/// <summary>
		/// 
		/// </summary>
		public byte MipmapMaxLevel = 255;

		/// <summary>
		/// 
		/// </summary>
		public float MipmapBias;

		/// <summary>
		/// 
		/// </summary>
		public readonly List<ColladaExtra>  Extras = new List<ColladaExtra>();

		#endregion

		#region COLLADA Support

		internal Texture Create()
		{
			ColladaFxSurface surface = null;
			ColladaFxProfile colladaProfile = (ColladaFxProfile) GetParent(delegate(ColladaXmlSerializable node)
           	{
           		return (node.GetType() == typeof(ColladaFxCommonProfile));
           	});

			// 
			switch (colladaProfile.ProfileName) {
				case ColladaFxCommonProfile.Profile:
					{
						ColladaFxCommonProfile commonProfile = (ColladaFxCommonProfile) colladaProfile;
						ColladaFxCommonNewParamType surfaceParam = commonProfile.NewParams.Find(delegate(ColladaFxCommonNewParamType param)
                     	{
							return (param.Sid == Source);
                     	});

						if (surfaceParam == null)
							throw new InvalidOperationException("no surface found");

						surface = (ColladaFxSurface) surfaceParam.Value.Value;
					}
					break;
				default:
					throw new NotSupportedException("not supported profile " + colladaProfile.ProfileName);
			}

			if (surface == null)
				throw new NotSupportedException();

			// 
			switch (Type) {
				case ColladaFxSamplerType.Sampler2D:
					{
						Texture2d texture = new Texture2d();
						Image textureImage = surface.CreateImage();

						// Texture contents defined by an image
						texture.Create(textureImage);

						return (texture);
					}
					break;
				default:
					throw new NotSupportedException(String.Format("sampler {0} no supported", Type));
			}
		}

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementSource) {
				Source = XmlHelper.ReadXmlTextElement(xmlReader);
			} else if (elementName == ColladaElementWrapS) {
				WrapS = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerWrap>(xmlReader);
			} else if (elementName == ColladaElementWrapT) {
				WrapT = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerWrap>(xmlReader);
			} else if (elementName == ColladaElementWrapP) {
				WrapP = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerWrap>(xmlReader);
			} else if (elementName == ColladaElementFilterMin) {
				FilterMin = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerFilter>(xmlReader);
			} else if (elementName == ColladaElementFilterMag) {
				FilterMag = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerFilter>(xmlReader);
			} else if (elementName == ColladaElementFilterMip) {
				FilterMip = XmlHelper.ReadXmlEnumElement<ColladaFxSamplerFilter>(xmlReader);
			} else if (elementName == ColladaElementBorderColor) {
				BorderColor = new ColladaFxColorType(this);
				BorderColor.ReadXml(xmlReader);
			} else if (elementName == ColladaElementMipMaxLevels) {
				MipmapMaxLevel = Byte.Parse(XmlHelper.ReadXmlTextElement(xmlReader), NumberFormatInfo.InvariantInfo);
			} else if (elementName == ColladaElementMipBias) {
				MipmapBias = Single.Parse(XmlHelper.ReadXmlTextElement(xmlReader), NumberFormatInfo.InvariantInfo);
			} else if (elementName == ColladaElementExtra) {
				ColladaExtra colladaExtra = new ColladaExtra(this);
				colladaExtra.ReadXml(xmlReader);
				Extras.Add(colladaExtra);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementSource = "source";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementWrapS = "wrap_s";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementWrapT = "wrap_t";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementWrapP = "wrap_p";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementFilterMin = "minfilter";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementFilterMag = "magfilter";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementFilterMip = "mipfilter";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementBorderColor = "border_color";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementMipMaxLevels = "mipmap_maxlevel";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementMipBias = "mipmap_bias";

		/// <summary>
		/// Collada 'sampler*' child element name (1.4).
		/// </summary>
		private const string ColladaElementExtra = "extra";

		#endregion
	}

	#endregion

	#region Surface Elements

	#region Surface Type Elements

	/// <summary>
	/// The fx_surface_type_enum enumeration.
	/// </summary>
	public enum ColladaFxSurfaceType
	{
		/// <summary>
		/// Untyped surface.
		/// </summary>
		/// <remarks>
		/// When a surface's type attribute is set to UNTYPED, its type is initially unknown and established later by the context in
		/// which it is used, such as by a texture sampler that references it. A surface of any other type may be changed into an UNTYPED
		/// surface at run-time, as if it were created by &lt;newparam&gt;, using &lt;setparam&gt;. If there is a type mismatch between a
		/// &lt;setparam&gt; operation and what the run-time decides the type should be, the result is profile- and platform-specific
		/// behavior.
		/// </remarks>
		[XmlEnum("UNTYPED")]
		Untyped,
		/// <summary>
		/// 1D surface.
		/// </summary>
		[XmlEnum("1D")]
		Surface1D,
		/// <summary>
		/// 2D surface.
		/// </summary>
		[XmlEnum("2D")]
		Surface2D,
		/// <summary>
		/// 3D surface.
		/// </summary>
		[XmlEnum("3D")]
		Surface3D,
		/// <summary>
		/// 2D rectangle surface.
		/// </summary>
		[XmlEnum("RECT")]
		SurfaceRect,
		/// <summary>
		/// 2D cube surface.
		/// </summary>
		[XmlEnum("CUBE")]
		SurfaceCube,
		/// <summary>
		/// Depth surface.
		/// </summary>
		[XmlEnum("DEPTH")]
		SurfaceDepth,
	}

	/// <summary>
	/// The fx_surface_type_enum enumeration.
	/// </summary>
	public enum ColladaFxSurfaceFace
	{
		[XmlEnum("POSITIVE_X")]
		PositiveX,
		[XmlEnum("NEGATIVE_X")]
		NegativeX,
		[XmlEnum("POSITIVE_Y")]
		PositiveY,
		[XmlEnum("NEGATIVE_Y")]
		NegativeY,
		[XmlEnum("POSITIVE_Z")]
		PositiveZ,
		[XmlEnum("NEGATIVE_Z")]
		NegativeZ,
	}

	/// <summary>
	/// The per-texel layout of the format. The length of the string indicate how many channels there are and the letter respresents
	/// the name of the channel.  There are typically 0 to 4 channels.
	/// </summary>
	public enum ColladaFxSurfaceFormatHintChannels
	{
		[XmlEnum("RGB")]
		RGB,
		[XmlEnum("RGBA")]
		RGBA,
		[XmlEnum("L")]
		L,
		[XmlEnum("LA")]
		LA,
		[XmlEnum("D")]
		D,
		[XmlEnum("XYZ")]
		XYZ,
		[XmlEnum("XYZW")]
		XYZW
	}

	/// <summary>
	/// Each channel of the texel has a precision. Typically these are all linked together. An exact format lay lower the precision
	/// of an individual channel but applying a higher precision by linking the channels together may still convey the same
	/// information.
	/// </summary>
	public enum ColladaFxSurfaceFormatHintPrecision
	{
		/// <summary>
		/// For integers this typically represents 8 bits. For floats typically 16 bits.
		/// </summary>
		[XmlEnum("LOW")]
		Low,
		/// <summary>
		/// For integers this typically represents 8 to 24 bits. For floats typically 16 to 32 bits.
		/// </summary>
		[XmlEnum("MED")]
		Medium,
		/// <summary>
		/// For integers this typically represents 16 to 32 bits.  For floats typically 24 to 32 bits.
		/// </summary>
		[XmlEnum("HIGH")]
		High
	}

	/// <summary>
	/// Each channel represents a range of values. Some example ranges are signed or unsigned integers, or between between a
	/// clamped range such as 0.0f to 1.0f, or high dynamic range via floating point.
	/// </summary>
	public enum ColladaFxSurfaceFormatHintRange
	{
		/// <summary>
		/// Format is representing a decimal value that remains within the -1 to 1 range. Implementation could be integer-fixedpoint or floats.
		/// </summary>
		[XmlEnum("SNORM")]
		SNORM,
		/// <summary>
		/// Format is representing a decimal value that remains within the 0 to 1 range. Implimentation could be integer-fixedpoint or floats.
		/// </summary>
		[XmlEnum("UNORM")]
		UNORM,
		/// <summary>
		/// Format is representing signed integer numbers.  (ex. 8bits = -128 to 127)
		/// </summary>
		[XmlEnum("SINT")]
		SINT,
		/// <summary>
		/// Format is representing unsigned integer numbers.  (ex. 8bits = 0 to 255)
		/// </summary>
		[XmlEnum("UINT")]
		UINT,
		/// <summary>
		/// Format should support full floating point ranges. High precision is expected to be 32bit. Mid precision may be 16 to 32 bit.
		/// Low precision is expected to be 16 bit.
		/// </summary>
		[XmlEnum("FLOAT")]
		FLOAT,
	}

	/// <summary>
	/// Additional hints about data relationships and other things to help the application pick the best format.
	/// </summary>
	public enum ColladaFxSurfaceFormatHintOption
	{
		/// <summary>
		/// Colors are stored with respect to the sRGB 2.2 gamma curve rather than linear.
		/// </summary>
		[XmlEnum("SRGB_GAMMA")]
		SRGB_GAMMA,
		/// <summary>
		/// The texel's XYZ/RGB should be normalized such as in a normal map.
		/// </summary>
		[XmlEnum("NORMALIZED3")]
		NORMALIZED3,
		/// <summary>
		///	The texel's XYZW/RGBA should be normalized such as in a normal map.
		/// </summary>
		[XmlEnum("NORMALIZED4")]
		NORMALIZED4,
		/// <summary>
		/// The surface may use run-time compression. Considering the best compression based on desired, channel, range, precision, and options.
		/// </summary>
		[XmlEnum("COMPRESSABLE")]
		COMPRESSABLE,
	}

	#endregion

	/// <summary>
	/// If the exact format cannot be resolve via other methods then the format_hint will describe the important
	/// features of the format so that the application may select a compatable or close format.
	/// </summary>
	public class ColladaFxSurfaceFormatHint : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceFormatHint.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceFormatHint.
		/// </param>
		public ColladaFxSurfaceFormatHint(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Surface Format Hint Information

		/// <summary>
		/// The per-texel layout of the format. The length of the string indicate how many channels there are and the letter
		/// respresents the name of the channel.  There are typically 0 to 4 channels.
		/// </summary>
		public ColladaFxSurfaceFormatHintChannels Channels;

		/// <summary>
		/// Each channel represents a range of values. Some example ranges are signed or unsigned integers, or between between a
		/// clamped range such as 0.0f to 1.0f, or high dynamic range via floating point.
		/// </summary>
		public ColladaFxSurfaceFormatHintRange Range;

		/// <summary>
		/// Each channel of the texel has a precision.  Typically these are all linked together.  An exact format lay lower
		/// the precision of an individual channel but applying a higher precision by linking the channels together may still
		/// convey the same information.
		/// </summary>
		public ColladaFxSurfaceFormatHintPrecision Precision;

		/// <summary>
		/// Additional hints about data relationships and other things to help the application pick the best format.
		/// </summary>
		public List<ColladaFxSurfaceFormatHintOption> Option;

		/// <summary>
		/// 
		/// </summary>
		public List<ColladaExtra> Extras;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Collada 'fx_surface_format_hint_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementChannels = "channels";

		/// <summary>
		/// Collada 'fx_surface_format_hint_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementRange = "range";

		/// <summary>
		/// Collada 'fx_surface_format_hint_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementPrecision = "precision";

		/// <summary>
		/// Collada 'fx_surface_format_hint_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementOption = "option";

		/// <summary>
		/// Collada 'fx_surface_format_hint_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementExtra = "extra";

		#endregion
	}

	/// <summary>
	/// The common set of initalization options for surfaces.  Choose which is appropriate for your surface based on type and other
	/// characteristics. described by the annotation docs on the child elements.
	/// </summary>
	public class ColladaFxSurfaceInit : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceInit.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceInit.
		/// </param>
		public ColladaFxSurfaceInit(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Collada FX Surface Initialization

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSurfaceInitNull NullInit;

		/// <summary>
		/// 
		/// </summary>
		public ColladaFxSurfaceInitTarget TargetInit;

		/// <summary>
		/// 
		/// </summary>
		public readonly List<ColladaFxSurfaceInitFrom> FromInits = new List<ColladaFxSurfaceInitFrom>();

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementInitFrom) {
				ColladaFxSurfaceInitFrom initFrom = new ColladaFxSurfaceInitFrom(this);
				initFrom.ReadXml(xmlReader);
				FromInits.Add(initFrom);
			} else if (elementName == ColladaElementInitNull) {
				NullInit = new ColladaFxSurfaceInitNull(this);
				NullInit.ReadXml(xmlReader);
			} else if (elementName == ColladaElementInitTarget) {
				TargetInit = new ColladaFxSurfaceInitTarget(this);
				TargetInit.ReadXml(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'init_from|init_nul|...' child element name (1.4).
		/// </summary>
		private const string ColladaElementInitNull = "init_null";

		/// <summary>
		/// Collada 'init_from|init_nul|...' child element name (1.4).
		/// </summary>
		private const string ColladaElementInitTarget = "init_target";

		/// <summary>
		/// Collada 'init_from|init_nul|...' child element name (1.4).
		/// </summary>
		private const string ColladaElementInitFrom = "init_from";

		#endregion
	}

	#region Surface Initialization Elements

	/// <summary>
	/// This surface is intended to be initialized later externally by a "setparam" element.  If it
	/// is used before being initialized there is profile and platform specific behavior.  Most elements on
	/// the surface element containing this will be ignored including mip_levels, mipmap_generate, size, viewport_ratio,
	/// and format.
	/// </summary>
	public class ColladaFxSurfaceInitNull : ColladaFxSurfaceInit
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceInitNull.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceInitNull.
		/// </param>
		public ColladaFxSurfaceInitNull(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion
	}

	/// <summary>
	/// Init as a target for depth, stencil, or color.  It does not need image data. Surface should not have mipmap_generate when using this.
	/// </summary>
	public class ColladaFxSurfaceInitTarget : ColladaFxSurfaceInit
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceInitTarget.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceInitTarget.
		/// </param>
		public ColladaFxSurfaceInitTarget(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion
	}

	/// <summary>
	/// For 1D, 2D, RECT surface types
	/// </summary>
	public class ColladaFxSurfaceInitPlanar : ColladaFxSurfaceInit
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceInitPlanar.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceInitPlanar.
		/// </param>
		public ColladaFxSurfaceInitPlanar(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion
	}

	/// <summary>
	/// This element is an IDREF which specifies the image to use to initialize a specific mip of a 1D or 2D surface, 3D slice, or Cube face.
	/// </summary>
	public class ColladaFxSurfaceInitFrom : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurfaceInitFrom.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurfaceInitFrom.
		/// </param>
		public ColladaFxSurfaceInitFrom(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Surface Initialization From Information

		/// <summary>
		/// The referenced image.
		/// </summary>
		public string IdRef;

		/// <summary>
		/// The mipmap level.
		/// </summary>
		public uint Level;

		/// <summary>
		/// 
		/// </summary>
		public uint Slice;

		/// <summary>
		/// Cube face (default to positive X).
		/// </summary>
		public ColladaFxSurfaceFace Face = ColladaFxSurfaceFace.PositiveX;

		#endregion

		#region COLLADA Support



		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeLevel]) != null)
				Level = UInt32.Parse(attribute);
			if ((attribute = xmlReader[ColladaAttributeSlice]) != null)
				Slice = UInt32.Parse(attribute);
			if ((attribute = xmlReader[ColladaAttributeFace]) != null)
				Face = XmlHelper.ReadXmlEnum<ColladaFxSurfaceFace>(attribute);
		}

		/// <summary>
		/// Read the element text of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		public override void ReadText(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			IdRef = XmlHelper.ReadXmlTextElement(xmlReader);
		}

		/// <summary>
		/// Collada 'init_from' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeLevel = "level";

		/// <summary>
		/// Collada 'init_from' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeSlice = "slice";

		/// <summary>
		/// Collada 'init_from' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeFace = "face";

		#endregion
	}

	#endregion

	/// <summary>
	/// The fx_surface_common type is used to declare a resource that can be used both as the source for texture samples and as the target of a rendering pass.
	/// </summary>
	public class ColladaFxSurface : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxSurface.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxSurface.
		/// </param>
		public ColladaFxSurface(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region COLLADA FX Surface Information

		/// <summary>
		/// Specifying the type of a surface is mandatory though the type may be "UNTYPED".  When a surface is
		/// typed as UNTYPED, it is said to be temporarily untyped and instead will be typed later by the context it is
		/// used in such as which samplers reference it in that are used in a particular technique or pass.
		/// If there is a type mismatch between what is set into it later and what the runtime decides the type should
		/// be the result in profile and platform specific behavior.
		/// </summary>
		public ColladaFxSurfaceType Type;

		/// <summary>
		/// The common set of initalization options for surfaces. Choose which is appropriate for your surface based on the type
		/// attribute and other characteristics described by the annotation docs on the choiced child elements of this type.
		/// </summary>
		public ColladaFxSurfaceInit SurfaceInit;

		/// <summary>
		/// Contains a string representing the profile and platform specific texel format that the author would like this
		/// surface to use. If this element is not specified then the application will use a common format R8G8B8A8 with
		/// linear color gradient, not sRGB.
		/// </summary>
		public string Format;

		/// <summary>
		/// If the exact format cannot be resolved via the "format" element then the format_hint will describe the important
		/// features of the format so that the application may select a compatable or close format.
		/// </summary>
		public ColladaFxSurfaceFormatHint FormatHint;

		/// <summary>
		/// The surface should be sized to these exact dimensions.
		/// </summary>
		public Vertex3i Size = new Vertex3i(0, 0, 0);

		/// <summary>
		/// The surface should be sized to a dimension based on this ratio of the viewport's dimensions in pixels
		/// </summary>
		public Vertex2f ViewportRatio = new Vertex2f(1.0f, 1.0f);

		/// <summary>
		/// The surface should contain the following number of MIP levels. If this element is not present it is assumed that
		/// all miplevels exist until a dimension becomes 1 texel.
		/// To create a surface that has only one level of mip maps (mip=0) set this to 1. 
		/// If the value is 0 the result is the same as if mip_levels was unspecified, all possible mip_levels will exist.
		/// </summary>
		public uint MipmapLevels;

		/// <summary>
		/// By default it is assumed that mipmaps are supplied by the author so, if not all subsurfaces are initialized, it
		/// is invalid and will result in profile and platform specific behavior unless mipmap_generate is responsible for
		/// initializing the remainder of the sub-surfaces
		/// </summary>
		public bool MipmapGenerate;

		/// <summary>
		/// 
		/// </summary>
		public readonly List<ColladaExtra> Extras = new List<ColladaExtra>();

		#endregion

		#region COLLADA Support

		internal Image CreateImage()
		{
			ColladaDocument colladaDocument = GetColladaDocument();

			if (SurfaceInit.FromInits.Count == 1) {
				foreach (ColladaLibraryImages libraryImages in colladaDocument.LibraryImages) {
					ColladaImage colladaImage = libraryImages.Resolve(SurfaceInit.FromInits[0].IdRef, colladaDocument);

					if (colladaImage != null)
						return (colladaImage.Create());
				}
				
				throw new InvalidOperationException(String.Format("unable to find image {0}", SurfaceInit.FromInits[0].IdRef));
			} else
				throw new InvalidOperationException();
		}

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read the attribute of the current XML serializable.
		/// </summary>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading XML element attributes.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is called only in the case there are effectively attributes on XML element. Don't expect that this
		/// method will be called even when the attributes count is zero. This is very important, since the design doesn't
		/// allow object initialization using this method.
		/// </para>
		/// </remarks>
		public override void ReadAttributes(XmlReader xmlReader)
		{
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			string attribute;

			if ((attribute = xmlReader[ColladaAttributeType]) == null)
				throw new InvalidOperationException("missing attribute " + ColladaAttributeType);
			Type = XmlHelper.ReadXmlEnum<ColladaFxSurfaceType>(attribute);
		}

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			if (elementName == ColladaElementFormat) {
				Format = XmlHelper.ReadXmlTextElement(xmlReader);
			} else if (elementName == ColladaElementFormatHint) {
				FormatHint = new ColladaFxSurfaceFormatHint(this);
				FormatHint.ReadXml(xmlReader);
			} else if (elementName == ColladaElementSize) {
				XmlHelper.SkipXmlElement(xmlReader);
			} else if (elementName == ColladaElementViewportRatio) {
				XmlHelper.SkipXmlElement(xmlReader);
			} else if (elementName == ColladaElementMipmapLevels) {
				MipmapLevels = UInt32.Parse(XmlHelper.ReadXmlTextElement(xmlReader));
			} else if (elementName == ColladaElementMipmapGenerate) {
				MipmapGenerate = Boolean.Parse(XmlHelper.ReadXmlTextElement(xmlReader));
			} else if (elementName == ColladaElementMipmapExtra) {
				ColladaExtra colladaExtra = new ColladaExtra(this);
				colladaExtra.ReadXml(xmlReader);
				Extras.Add(colladaExtra);
			} else if (Regex.IsMatch(elementName, ColladaElementInit)) {
				SurfaceInit = new ColladaFxSurfaceInit(this);
				SurfaceInit.ReadElement(elementName, xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'fx_annotate_common' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeType = "type";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInit = @"init_\w+";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFormat = "format";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFormatHint = "format_hint";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementSize = "size";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementViewportRatio = "viewport_ratio";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementMipmapLevels = "mip_levels";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementMipmapGenerate = "mipmap_generate";

		/// <summary>
		/// Collada 'fx_surface_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementMipmapExtra = "extra";

		#endregion
	}

	#endregion

	/// <summary>
	/// A group that specifies the allowable types for effect scoped parameters.
	/// </summary>
	public class ColladaFxBasicType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxBasicType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxBasicType.
		/// </param>
		public ColladaFxBasicType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Basic Type Information

		/// <summary>
		/// Determine whether it is a known element.
		/// </summary>
		/// <param name="element"></param>
		/// <returns></returns>
		public static bool IsKnownElement(string element)
		{
			if (element == null)
				throw new ArgumentNullException("element");

			switch (element) {
				case ColladaElementEnum:
				case ColladaElementSurface:
					return (true);
				default:
					return (sArrayRegex.IsMatch(element) || sMatrixRegex.IsMatch(element) || sSamplerRegex.IsMatch(element));
			}
		}

		/// <summary>
		/// The value.
		/// </summary>
		public object Value;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Read an element of the current XML serializable.
		/// </summary>
		/// <param name="elementName">
		/// A <see cref="System.String"/> that specify the element name.
		/// </param>
		/// <param name="xmlReader">
		/// A <see cref="XmlReader"/> used for reading child element. It is positioned at the start element.
		/// </param>
		/// <remarks>
		/// <para>
		/// This method is responsible to read the start element of the nested element.
		/// </para>
		/// <para>
		/// This method is resposible to read all children elements till the corresponding end element, without reading it. In the
		/// case this condition is not satisfied, the XML parsing will be aborted.
		/// </para>
		/// </remarks>
		public override void ReadElement(string elementName, XmlReader xmlReader)
		{
			if (elementName == null)
				throw new ArgumentNullException("elementName");
			if (xmlReader == null)
				throw new ArgumentNullException("xmlReader");

			Match match;

			if ((match = sArrayRegex.Match(elementName)).Success) {
				Type valueType = Type.GetType(match.Groups["Type"].Value);
				uint length = 1;

				if (valueType == null)
					throw new NotSupportedException(String.Format("basic type '{0}' not supported", match.Groups["Type"].Value));
				
				// Determine length
				if (match.Groups["Length"].Captures.Count > 0)
					length = UInt32.Parse(match.Groups["Length"].Value);

				// Determine element tokens
				string[] valueArray = XmlHelper.ReadXmlTextElement(xmlReader).Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

				if (valueArray.Length != length)
					throw new InvalidOperationException("array length mismatch");

				if (length > 1) {
					if        (valueType == typeof(float)) {
						float[] arrayValue = new float[length];

						for (uint i = 0; i < length; i++)
							arrayValue[i] = Single.Parse(valueArray[i], NumberFormatInfo.InvariantInfo);
						Value = arrayValue;

					} else if (valueType == typeof(int)) {
						int[] arrayValue = new int[length];

						for (uint i = 0; i < length; i++)
							arrayValue[i] = Int32.Parse(valueArray[i], NumberFormatInfo.InvariantInfo);
						Value = arrayValue;

					} else if (valueType == typeof(bool)) {
						bool[] arrayValue = new bool[length];

						for (uint i = 0; i < length; i++)
							arrayValue[i] = Boolean.Parse(valueArray[i]);
						Value = arrayValue;

					}
				} else {
					if        (valueType == typeof(float)) {
						Value = Single.Parse(valueArray[0], NumberFormatInfo.InvariantInfo);
					} else if (valueType == typeof(int)) {
						Value = Int32.Parse(valueArray[0], NumberFormatInfo.InvariantInfo);
					} else if (valueType == typeof(bool)) {
						Value = Boolean.Parse(valueArray[0]);
					}
				}
			} else if ((match = sMatrixRegex.Match(elementName)).Success) {
				throw new NotSupportedException();
			} else if ((match = sSamplerRegex.Match(elementName)).Success) {
				ColladaFxSampler colladaSampler;

				switch (elementName) {
					case "sampler1D":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.Sampler1D, this);
						break;
					case "sampler2D":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.Sampler2D, this);
						break;
					case "sampler3D":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.Sampler3D, this);
						break;
					case "samplerCUBE":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.SamplerCube, this);
						break;
					case "samplerRECT":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.SamplerRect, this);
						break;
					case "samplerDEPTH":
						colladaSampler = new ColladaFxSampler(ColladaFxSamplerType.SamplerDepth, this);
						break;
					default:
						throw new NotSupportedException("unknown sampler type " + elementName);
				}

				colladaSampler.ReadXml(xmlReader);
				Value = colladaSampler;
			} else if (elementName == ColladaElementSurface) {
				ColladaFxSurface colladaSurface = new ColladaFxSurface(this);
				colladaSurface.ReadXml(xmlReader);
				Value = colladaSurface;
			} else if (elementName == ColladaElementEnum) {
				// Value as string
				Value = XmlHelper.ReadXmlTextElement(xmlReader);
			} else
				base.ReadElement(elementName, xmlReader);
		}

		/// <summary>
		/// Collada 'fx_basic_type_common' child element name (1.4).
		/// </summary>
		/// <remarks>
		/// This regex includes bool, bool2, bool3, bool4, int, int1, int2, int3, int4, float1, float2, float3 and
		/// float4.
		/// </remarks>
		private static readonly Regex sArrayRegex = new Regex(@"^(?<Type>bool|int|float)(?<Length>[2-4])?$");

		/// <summary>
		/// Collada 'fx_basic_type_common' child element name (1.4).
		/// </summary>
		/// <remarks>
		/// This regex matches float1x1, float1x2, float1x3, float1x4, float2x1, float2x2, float2x3, float2x4,
		/// float3x1, float3x2, float3x3, float3x4, float4x1, float4x2, float4x3 and float4x4.
		/// </remarks>
		private static readonly Regex sMatrixRegex = new Regex(@"^float(?<Width>[1-4])x(?<Height>[1-4])$");

		/// <summary>
		/// Collada 'fx_basic_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementSurface = "surface";

		/// <summary>
		/// Collada 'fx_basic_type_common' child element name (1.4).
		/// </summary>
		/// <remarks>
		/// This regex matches sampler1D, sampler2D, sampler3D, samplerCUBE, samplerRECT, samplerDEPTH.
		/// </remarks>
		private static readonly Regex sSamplerRegex = new Regex(@"(?<Object>sampler1D|sampler2D|sampler3D|samplerCUBE|samplerRECT|samplerDEPTH)");

		/// <summary>
		/// Collada 'fx_basic_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementEnum = "enum";

		#endregion
	}

	/// <summary>
	/// A group that specifies the allowable types for an annotation.
	/// </summary>
	public class ColladaFxAnnotateType : ColladaXmlSerializable
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxAnnotateType.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxAnnotateType.
		/// </param>
		public ColladaFxAnnotateType(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Annotate Type Information

		/// <summary>
		/// The value.
		/// </summary>
		public object Value;

		#endregion

		#region ColladaXmlSerializable Overrides

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementBool = "bool";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementBool2 = "bool2";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementBool3 = "bool3";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementBool4 = "bool4";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInt = "int";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInt1 = "int1";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInt2 = "int2";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInt3 = "int3";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementInt4 = "int4";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat = "float";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat2 = "float2";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat3 = "float3";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat4 = "float4";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat2x2 = "float2x2";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat3x3 = "float3x3";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementFloat4x4 = "float4x4";

		/// <summary>
		/// Collada 'fx_annotate_type_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementString = "string";

		#endregion
	}

	/// <summary>
	/// An element that specifies the allowable types for an annotation.
	/// </summary>
	public class ColladaFxAnnotate : ColladaFxAnnotateType
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxAnnotate.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxAnnotate.
		/// </param>
		public ColladaFxAnnotate(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX Annotate Information

		/// <summary>
		/// The name attribute is the text string name of this element. Required attribute.
		/// </summary>
		public string Name;

		#endregion

		#region ColladaCommonFxAnnotateType Overrides

		/// <summary>
		/// Collada 'fx_annotate_common' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeName = "name";

		#endregion
	}

	/// <summary>
	/// This element creates a new, named param object in the FX Runtime, assigns it a type, an initial value, and
	/// additional attributes at declaration time.
	/// </summary>
	public class ColladaFxNewParam : ColladaFxBasicType
	{
		#region Constructors

		/// <summary>
		/// Construct a ColladaFxNewParam.
		/// </summary>
		/// <param name="parent">
		/// The parent element containing this ColladaFxNewParam.
		/// </param>
		public ColladaFxNewParam(ColladaXmlSerializable parent) : base(parent)
		{
			
		}

		#endregion

		#region Common FX New Param Information

		/// <summary>
		/// The annotate element allows you to specify an annotation for this new param.
		/// </summary>
		public List<ColladaFxAnnotate> Annotates = new List<ColladaFxAnnotate>();

		/// <summary>
		/// The semantic element allows you to specify a semantic for this new param.
		/// </summary>
		public string Semantic;

		/// <summary>
		/// The modifier element allows you to specify a modifier for this new param.
		/// </summary>
		public ColladaFxModifier Modifier = ColladaFxModifier.None;

		#endregion

		#region ColladaCommonFxBasicType Overrides

		/// <summary>
		/// Collada 'fx_newparam_common' attribute name (1.4).
		/// </summary>
		private const string ColladaAttributeSid = "sid";

		/// <summary>
		/// Collada 'fx_newparam_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementAnnotate = "annotate";

		/// <summary>
		/// Collada 'fx_newparam_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementSemantic = "semantic";

		/// <summary>
		/// Collada 'fx_newparam_common' child element name (1.4).
		/// </summary>
		private const string ColladaElementModifier = "modifier";

		#endregion
	}
}
